﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using KBEngineTool.Core;
using KBEngineTool.Export;
using KBEngine.Common;
using KBEngine.Setting.TypeDef;

namespace KBEngineTool.UI
{
    public partial class MainWindow : Form
    {
        Process process = new Process();
        public string version = "V1.021 开发版";
     
        public MainWindow()
        {
            InitializeComponent();
           
            // Add the control scroll message filter to re-route all mousewheel events
            // to the control the user is currently hovering over with their cursor.

            //name = System.Console.ReadLine();
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            KBEngine.Event.registerOut(MainWindow_Event.RefreshEntityTree, RefreshEntityTree);
            KBEngine.Event.registerOut(MainWindow_Event.RefreshTypePanel, RefreshTypePanel);
            KBEngine.Event.registerOut(MainWindow_Event.UpdateNodeName, this, nameof(UpdateNodeName));
            KBEngine.Event.registerOut(MainWindow_Event.AddWidget, this, nameof(__AddWidget));
            KBEngine.Event.registerOut(MainWindow_Event.RefreshPanel, this, nameof(__RefreshPanel));
            KBEngine.Event.registerOut(KBEngine.MachineEvent.OnQueryAllInterfaces, this, nameof(__OnQueryAllInterfaces));

#if DEBUG
            Log.Inst.AddLogDevices(new DebugLog());
#else
            //Log.Inst.AddLogDevices(new ConsoleLog());
            Log.Inst.AddLogDevices(new FileLog(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "/ToolsLog", true));
#endif
            TypeDefInitialize();
            EntityDefInitialize();

            //自动打开工程
            var gSetting = Properties.Settings.Default;
            var lastOpenProject = gSetting.LastOpenProject;
            if (!string.IsNullOrEmpty(lastOpenProject) && Directory.Exists(lastOpenProject))
                OpenProject(lastOpenProject);

            //添加工程记录
            ToolStripItem[] menuItemList = new ToolStripItem[gSetting.OpenProjectRecord.Count];
            for (int i = 0; i < gSetting.OpenProjectRecord.Count; i++)
            {
                var item = gSetting.OpenProjectRecord[i];
                ToolStripItem toolStripItem = new ToolStripMenuItem(item);
                toolStripItem.Click += MenuItem_Record_Click;
                menuItemList[i] = toolStripItem;
            }
            menuItemList.Reverse();
            MenuItem_Record.DropDownItems.AddRange(menuItemList);
        }

        private void MenuItem_Record_Click(object sender, EventArgs e)
        {
            var menuItem = (ToolStripItem)sender;
            if (OpenProject(menuItem.Text))
                return;
            if (MessageBox.Show($"打开工程 {menuItem.Text} 失败, 是否移除此项.", "提示", MessageBoxButtons.YesNo) == DialogResult.OK)
            {
                var gSetting = Properties.Settings.Default;
                gSetting.OpenProjectRecord.Remove(menuItem.Text);
                menuItem.GetCurrentParent().Items.Remove(menuItem);
            }
        }
        private void MainWindow_FormClosed(object sender, FormClosedEventArgs e)
        {
            Log.Inst.Dispose();
        }

#region TypeDef

        List<KeyValuePair<Func<Point>, Func<Point>>> m_pannelLines = new List<KeyValuePair<Func<Point>, Func<Point>>>();
        TreeNode m_rootNode;

        List<BaseType> AllTypes
        {
            get { return EntityDef.AllTypes; }
        }

        void TypeDefInitialize()
        {
            InitTreeView();
        }

        void InitTreeView()
        {
            m_rootNode = new TreeNode("AllTypes");
            m_typeTreeView.Nodes.Add(m_rootNode);

            foreach (var item in AllTypes)
                AddNodeToTree(item);

            m_typeTreeView.ExpandAll();
        }

#region Compoment Events

        private void m_treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            RefreshTypePanel();
        }

        private void m_treeView_MouseUp(object sender, MouseEventArgs e)
        {
            if (!Operation.Inst.IsOpenProj)
                return;
            if (e.Button != MouseButtons.Right)
                return;

            ContextMenu con = new ContextMenu();

            MenuItem newType = new MenuItem("新建类型");
            newType.Click += new EventHandler(OnClick_CreateNewType);
            con.MenuItems.Add(newType);

            MenuItem delType = new MenuItem("删除类型");
            delType.Click += new EventHandler(OnClick_DeleteType);
            con.MenuItems.Add(delType);

            TreeNode tn = m_typeTreeView.GetNodeAt(e.X, e.Y);
            if (tn != null) m_typeTreeView.SelectedNode = tn;
            delType.Enabled = tn != null && tn.Tag != null && tn.Tag.GetType() != typeof(BaseType);

            m_typeTreeView.ContextMenu = con;
            con.Show(m_typeTreeView, new Point(e.X + 10, e.Y));
            m_typeTreeView.ContextMenu = null;
        }

        private void m_panel_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.Black);
            var p = m_type_panel.PointToScreen(Point.Empty);
            System.Drawing.Size ps = new Size(p);
            foreach (var item in m_pannelLines)
            {

                e.Graphics.DrawLine(pen, Point.Subtract(item.Key(), ps), Point.Subtract(item.Value(), ps));
            }
        }

#endregion

        private void OnClick_CreateNewType(object sender, EventArgs e)
        {
            TypeChooseWindow typeChooseWindow = new TypeChooseWindow();
            typeChooseWindow.ShowDialog();

            if (typeChooseWindow.DialogResult == System.Windows.Forms.DialogResult.OK)
                CreateNewType(typeChooseWindow.Type, typeChooseWindow.TypeName);
        }

        private void CreateNewType(Type type, string typeName)
        {
            BaseType t = null;
            if (type == typeof(AliasType))
            {
                t = new AliasType(typeName, null);
                AllTypes.Add(t);
                AddNodeToTree(t);
            }

            if (type == typeof(UserType))
            {
                t = new UserType(typeName);
                AllTypes.Add(t);
                AddNodeToTree(t);
            }

            RefershTypeTreeView();

            foreach (TreeNode item in m_rootNode.Nodes)
            {
                if (item.Text == typeName)
                {
                    m_typeTreeView.SelectedNode = item;
                    break;
                }
            }
        }

        public void RefershTypeTreeView()
        {
            AllTypes.Sort((a, b) =>
           {
               if (a.GetType() == b.GetType())
                   return a.TypeName.CompareTo(b.TypeName);

               if (a.GetType() == typeof(BaseType) || b.GetType() == typeof(UserType))
                   return -1;

               if (a.GetType() == typeof(UserType) || b.GetType() == typeof(BaseType))
                   return 1;

               throw new Exception();
           });

            int index = 0;
            foreach (TreeNode item in m_rootNode.Nodes)
            {
                var type = AllTypes[index++];
                item.Tag = type;
                item.Text = type.TypeName;
                UpdateNodeColor(item);
                if (index == AllTypes.Count)
                    break;
            }

            for (int i = index; i < m_rootNode.Nodes.Count; i++)
                m_rootNode.Nodes.RemoveAt(i);

            for (int i = index; i < AllTypes.Count; i++)
                AddNodeToTree(AllTypes[i]);
            m_rootNode.ExpandAll();
        }

        private void OnClick_DeleteType(object sender, EventArgs e)
        {
            var selectedType = m_typeTreeView.SelectedNode.Tag as BaseType;

            if (selectedType.GetType() == typeof(BaseType))
            {
                MessageBox.Show("基础类型不能删除");
                return;
            }

            BaseType referenecedBy = null;

            foreach (var item in EntityDef.AllTypes)
            {
                if (item.GetType() == typeof(BaseType))
                    continue;

                var aliasType = item as AliasType;
                if (aliasType != null && IsReferencedType(aliasType.RealType, selectedType))
                {
                    referenecedBy = item;
                    break;
                }

                var userType = item as UserType;
                if (userType != null)
                {
                    foreach (var t in userType.Properties)
                    {
                        if (IsReferencedType(t.Type, selectedType))
                        {
                            referenecedBy = item;
                            break;
                        }
                    }
                }
                if (referenecedBy != null)
                    break;
            }

            if (referenecedBy != null)
                MessageBox.Show(string.Format("无法删除\n类型'{0}'被其他类型'{1}'引用", selectedType.TypeName, referenecedBy.TypeName));
            else
            {
                AllTypes.Remove(selectedType);
                m_rootNode.Nodes.Remove(m_typeTreeView.SelectedNode);
            }
        }

        private bool IsReferencedType(IType type, BaseType reference)
        {
            if (type == reference)
                return true;

            if (type.GetType() == typeof(BaseType))
                return false;

            var aliasType = type as AliasType;
            if (aliasType != null)
                return IsReferencedType(aliasType.RealType, reference);

            var arrayType = type as ArrayType;
            if (arrayType != null)
                return IsReferencedType(arrayType.ElementType, reference);

            var userType = type as UserType;
            if (userType != null)
            {
                foreach (var item in userType.Properties)
                    if (IsReferencedType(item.Type, reference))
                        return true;
                return false;
            }

            throw new Exception();
        }

        private void AddNodeToTree(IType t)
        {
            TreeNode node = new TreeNode(t.TypeName);
            node.Tag = t;
            m_rootNode.Nodes.Add(node);
            UpdateNodeColor(node);
        }

        private static void UpdateNodeColor(TreeNode node)
        {
            if (node.Tag.GetType() == typeof(BaseType))
                node.ForeColor = Color.Black;

            if (node.Tag.GetType() == typeof(AliasType))
                node.ForeColor = Color.Green;

            if (node.Tag.GetType() == typeof(UserType))
                node.ForeColor = Color.Brown;
        }

        public void UpdateNodeName(BaseType type)
        {
            foreach (TreeNode item in m_rootNode.Nodes)
            {
                if (item.Tag == type)
                {
                    item.Text = type.TypeName;
                    break;
                }
            }
        }

        public void RefreshTypePanel()
        {
            var nodeTag = m_typeTreeView.SelectedNode.Tag;
            Operation.Inst.CurrentSelectedType = nodeTag as IType;

            m_type_panel.Controls.Clear();
            m_pannelLines.Clear();

            if (nodeTag == null)
                return;

            if (nodeTag.GetType() == typeof(BaseType))
                m_type_panel.Controls.Add(new BaseTypeWidget(nodeTag as BaseType));

            if (nodeTag.GetType() == typeof(AliasType))
                m_type_panel.Controls.Add(new AliasTypeWidget(nodeTag as AliasType));

            if (nodeTag.GetType() == typeof(UserType))
                m_type_panel.Controls.Add(new UserTypeWidget(nodeTag as UserType));

            m_type_panel.Refresh();
        }

        public void __AddWidget(Control widget, Func<Point> start, Func<Point> end, bool refresh)
        {
            m_type_panel.Controls.Add(widget);
            m_pannelLines.Add(new KeyValuePair<Func<Point>, Func<Point>>(start, end));
            if (refresh)
                m_type_panel.Refresh();
        }

        public void __RefreshPanel()
        {
            m_type_panel.Refresh();
        }

#endregion

#region EntityDef

        Dictionary<string, EntityDef> AllEntites
        {
            get { return EntityDef.AllEntityDefs; }
        }
        EntityDefWidget m_entityWidget;
        void EntityDefInitialize()
        {
            m_entityWidget = new EntityDefWidget();
            m_entity_panel.Controls.Add(m_entityWidget);
            m_entityWidget.Dock = DockStyle.Fill;
        }

        public void RefreshEntityTree()
        {
            m_entityTreeView.Nodes.Clear();

            foreach (var item in AllEntites)
            {
                TreeNode t = new TreeNode(item.Key);
                t.Tag = item.Value;
                if (item.Value.EntityType == ClassType.Interfaces)
                    t.ForeColor = Color.Blue;
                else if (item.Value.EntityType == ClassType.Components)
                    t.ForeColor = Color.Green;
                m_entityTreeView.Nodes.Add(t);
            }
        }

        private void m_entityTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            m_entityWidget.Reset((EntityDef)e.Node.Tag);
        }
        private void m_entityTreeView_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            if (!m_entityWidget.ValidateEntityDefData())
                e.Cancel = true;
            Log.Debug((e.Node.Tag as EntityDef).Name);
        }
        private void m_entityTreeView_MouseUp(object sender, MouseEventArgs e)
        {
            if (!Operation.Inst.IsOpenProj)
                return;
            if (e.Button != MouseButtons.Right || !m_entityWidget.ValidateEntityDefData())
                return;
            ContextMenu con = new ContextMenu();

            MenuItem newType = new MenuItem("新建类型");
            newType.Click += new EventHandler(OnClick_CreateNewEntityDef);
            con.MenuItems.Add(newType);

            MenuItem delType = new MenuItem("删除类型");
            delType.Click += new EventHandler(OnClick_DeleteEctityDef);
            con.MenuItems.Add(delType);
            TreeNode tn = m_entityTreeView.GetNodeAt(e.X, e.Y);
            if (tn != null) m_entityTreeView.SelectedNode = tn;
            delType.Enabled = tn != null && tn.Tag != null;

            m_entityTreeView.ContextMenu = con;
            con.Show(m_entityTreeView, new Point(e.X + 10, e.Y));
            m_entityTreeView.ContextMenu = null;
        }

        private void OnClick_DeleteEctityDef(object sender, EventArgs e)
        {
            var entity = m_entityTreeView.SelectedNode.Tag as EntityDef;
            if (entity != null)
            {
                if (MessageBox.Show(string.Format("确定删除‘{0}’实体吗", entity.Name), "delete", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    AllEntites.Remove(entity.Name);
                    RefreshEntityTree();
                }
            }
        }
        private void OnClick_CreateNewEntityDef(object sender, EventArgs e)
        {
            string entityName = null;
            for (int i = 0; i < 9999; i++)
            {
                entityName = "Entity" + i.ToString();
                if (!AllEntites.Values.Any(a => a.Name == entityName))
                    break;
            }
            if (string.IsNullOrEmpty(entityName))
                entityName = Guid.NewGuid().ToString();

            var entity = new EntityDef(entityName, false);
            AllEntites.Add(entity.Name, entity);
            RefreshEntityTree();
            foreach (TreeNode item in m_entityTreeView.Nodes)
            {
                if (item.Tag == entity)
                {
                    m_entityTreeView.SelectedNode = item;
                    break;
                }
            }
        }

#endregion

        public void __OnQueryAllInterfaces()
        {
            m_TSSL_machineCount.Text = string.Format("machine:{0}", Operation.Inst.ClientApp.MachineList.Count);
        }

        void startpress(string file)
        {
            process.StartInfo.FileName = file;   // 初始化可执行文件名
            process.StartInfo.WorkingDirectory = SlnConfig.Inst.assetFolder; // 初始化可执行文件的文件夹信息
            if (File.Exists(Path.Combine(SlnConfig.Inst.assetFolder, file)))
            {
                // 当我们需要给可执行文件传入参数时候可以设置这个参数
                // "para1 para2 para3" 参数为字符串形式，每一个参数用空格隔开
                process.StartInfo.Arguments = "";
                process.StartInfo.UseShellExecute = true;        // 使用操作系统shell启动进程

                // 启动可执行文件
                process.Start();
            }
            else
            {
                MessageBox.Show("文件不存在，请将此软件放在资产目录下");
            }
        }

        private bool OpenProject(string assetFolder)
        {
            if (!Operation.Inst.OpenProject(assetFolder))
            {
                MessageBox.Show("请选择kbe资产目录");
                return false;
            }
            RefershTypeTreeView();
            RefreshEntityTree();
            var gSetting = Properties.Settings.Default;
            gSetting.LastOpenProject = assetFolder;
            if (!gSetting.OpenProjectRecord.Contains(assetFolder))
                gSetting.OpenProjectRecord.Add(assetFolder);
            if (gSetting.OpenProjectRecord.Count > gSetting.RecordCount)
                gSetting.OpenProjectRecord.RemoveAt(0);
            this.Text = Path.GetFileNameWithoutExtension(assetFolder) + "--KBEngine开发工具，联系QQ 67172435，QQ群 981976371  " + version;
            Properties.Settings.Default.Save();
            return true;
        }

        private void 打开CtrlOToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Ookii.Dialogs.VistaFolderBrowserDialog folderBrowser = new Ookii.Dialogs.VistaFolderBrowserDialog();
            folderBrowser.SelectedPath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            folderBrowser.Description = "选择KBEngine资产目录";
            if (folderBrowser.ShowDialog() != DialogResult.OK)
                return;

            OpenProject(folderBrowser.SelectedPath);
        }
        private void 保存CtrlSToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Operation.Inst.IsOpenProj)
            {
                MessageBox.Show("请先打开项目");
                return;
            }
            m_entityWidget.ValidateEntityDefData();
            EntityDef.WriteToFile(SlnConfig.Inst.userTypeFolder);
            MessageBox.Show("保存成功");
        }
        private void 刷新RToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Operation.Inst.IsOpenProj)
            {
                MessageBox.Show("请先打开项目");
                return;
            }
            EntityDef.LoadFromFile(SlnConfig.Inst.entityDefFolder, SlnConfig.Inst.entitiesXML, SlnConfig.Inst.typesXML);
            RefershTypeTreeView();
            RefreshEntityTree();
        }

        private void 导出CToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Operation.Inst.IsOpenProj)
            {
                MessageBox.Show("请先打开项目");
                return;
            }

            if (string.IsNullOrEmpty(ToolConfig.Inst.CSharpCodeDir))
            {
                var folderBrowser = new FolderBrowserDialog();
                if (folderBrowser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    ToolConfig.Inst.CSharpCodeDir = folderBrowser.SelectedPath;
                    ToolConfig.Inst.Save();
                }
            }

            if (!string.IsNullOrEmpty(ToolConfig.Inst.CSharpCodeDir))
            {
                var export = new CSharpCodeExport(EntityDef.AllTypes);
                if (export.Save(ToolConfig.Inst.CSharpCodeDir))
                    MessageBox.Show(string.Format("CSharp Code 导出成功: {0}\\{1}", ToolConfig.Inst.CSharpCodeDir, CSharpCodeExport.FileName));
            }
            else
                MessageBox.Show("请选择CSharp代码导出目录");
        }

        private void 不隐藏运行ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            startpress("start_server_background.bat");
        }
        private void 不隐藏运行ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            startpress("start_server.bat");
        }
        private void killToolStripMenuItem_Click(object sender, EventArgs e)
        {
            startpress("kill_server.bat");
        }
        private void guiconsoleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            startpress("guiconsole.bat");
        }
        private void 生成插件ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            startpress("gensdk.bat");
        }
        private void 导出提示代码ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (!Operation.Inst.IsOpenProj)
            {
                MessageBox.Show("请先打开项目");
                return;
            }


            if (string.IsNullOrEmpty(ToolConfig.Inst.TipsCodeDir))
            {
                Ookii.Dialogs.VistaFolderBrowserDialog folderBrowser = new Ookii.Dialogs.VistaFolderBrowserDialog();
                folderBrowser.SelectedPath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
                folderBrowser.Description = "选择提示代码目录";
                if (folderBrowser.ShowDialog() == DialogResult.OK)
                {
                    ToolConfig.Inst.TipsCodeDir = folderBrowser.SelectedPath;
                    ToolConfig.Inst.Save();
                }
            }

            if (!string.IsNullOrEmpty(ToolConfig.Inst.TipsCodeDir))
            {
                var export = new PythonTipsExport();
                if (export.Save(ToolConfig.Inst.TipsCodeDir))
                    MessageBox.Show(string.Format("Python Tips Code 导出成功: {0}", ToolConfig.Inst.TipsCodeDir));
            }
            else
                MessageBox.Show("请选择Python Tips代码导出目录");
        }

        private void 查看帮助ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://kbengine.github.io//cn/docs/");
        }
        private void gitHubToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://github.com/kbengine/kbengine");
        }

        private void 选项OToolStripMenuItem_Click(object sender, EventArgs e)
        {
            KBESettings kBESettings = new KBESettings();
            kBESettings.Show(this);
        }

        private void toolStripSplitBtn_Start_ButtonClick(object sender, EventArgs e)
        {
            Operation.Inst.ClientApp.QueryAllMachineInfos();
        }
    }
}
